{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 前馈神经网络———Tensorflow代码部分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "import numpy as np\n",
    "import random"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "导入Mnist数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting MNIST-data\\train-images-idx3-ubyte.gz\n",
      "Extracting MNIST-data\\train-labels-idx1-ubyte.gz\n",
      "Extracting MNIST-data\\t10k-images-idx3-ubyte.gz\n",
      "Extracting MNIST-data\\t10k-labels-idx1-ubyte.gz\n",
      "<class 'tensorflow.contrib.learn.python.learn.datasets.base.Datasets'>\n",
      "Training data shape: (55000, 784)\n",
      "Test data shape: (10000, 784)\n",
      "Validation data shape: (5000, 784)\n",
      "Training label shape: (55000, 10)\n"
     ]
    }
   ],
   "source": [
    "from tensorflow.examples.tutorials.mnist import input_data\n",
    "\n",
    "mnist = input_data.read_data_sets('MNIST-data', one_hot=True)\n",
    "\n",
    "print(type(mnist))  # <class 'tensorflow.contrib.learn.python.learn.datasets.base.Datasets'>\n",
    "print('Training data shape:', mnist.train.images.shape)  # Training data shape: (55000, 784)\n",
    "print('Test data shape:', mnist.test.images.shape)  # Test data shape: (10000, 784)\n",
    "print('Validation data shape:', mnist.validation.images.shape)  # Validation data shape: (5000, 784)\n",
    "print('Training label shape:', mnist.train.labels.shape)  # Training label shape: (55000, 10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "定义一个network类，实现全连接网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "class network(object):\n",
    "    '''\n",
    "    全连接神经网络\n",
    "    '''\n",
    "\n",
    "    def __init__(self, sizes):\n",
    "        '''\n",
    "        注意程序中op变量只需要初始化一遍就可以，在fit()中初始化\n",
    "        sizes：list传入每层神经元个数\n",
    "        '''\n",
    "        # 保存参数\n",
    "        self.__sizes = sizes\n",
    "        # 神经网络每一层的神经元个数数组类型\n",
    "        self.sizes = tf.placeholder(tf.int64, shape=[1, len(sizes)])\n",
    "        # 计算神经网络层数 包括输入层\n",
    "        self.num_layer = tf.size(self.sizes)\n",
    "        # 随机初始化权重  第i层和i+1层之间的权重向量\n",
    "        self.weights = [self.weight_variable(shape=(x, y)) for x, y in zip(sizes[:-1], sizes[1:])]\n",
    "        # 随机初始化偏置  第i层的偏置向量  i=1...num_layers  注意不可以设置shape=(x,1)\n",
    "        self.biases = [self.bias_variable(shape=[x, ]) for x in sizes[1:]]\n",
    "\n",
    "        # 输入样本和输出类别变量\n",
    "        self.x_ = tf.placeholder(tf.float32, shape=[None, sizes[0]])\n",
    "        self.y_ = tf.placeholder(tf.float32, shape=[None, sizes[-1]])\n",
    "\n",
    "        # 设置tensorflow对GPU使用按需分配\n",
    "        config = tf.ConfigProto()\n",
    "        config.gpu_options.allow_growth = False\n",
    "        self.sess = tf.InteractiveSession(config=config)\n",
    "\n",
    "    def weight_variable(self, shape):\n",
    "        \n",
    "        #Question1:请自行初始化权值\n",
    "        \n",
    "        return tf.Variable(initial)\n",
    "\n",
    "    def bias_variable(self, shape):\n",
    "\n",
    "        #初始化偏重\n",
    "        initial = tf.truncated_normal(shape, mean=0.0, stddev=1.0 / shape[0])  # 方差为1/nin\n",
    "        return tf.Variable(initial)\n",
    "\n",
    "    def feedforward(self, x):\n",
    "        '''\n",
    "        构建阶段：前向反馈\n",
    "        x:变量op,tf.placeholder()类型变量\n",
    "        返回一个op\n",
    "        '''\n",
    "        # 计算隐藏层\n",
    "        output = x\n",
    "        for i in range(len(self.__sizes) - 1):\n",
    "            b = self.biases[i]\n",
    "            w = self.weights[i]\n",
    "            if i != len(self.__sizes) - 2:\n",
    "                #Question2：若不是最后一层，经过则通过relu函数，请实现。\n",
    "                output = \n",
    "            else:\n",
    "                output = tf.nn.softmax(tf.matmul(output, w) + b)\n",
    "        return output\n",
    "\n",
    "    def fit(self, training_x, training_y, learning_rate=0.001, batch_size=64, epochs=10):\n",
    "        '''\n",
    "        训练神经网络\n",
    "        x：训练集样本\n",
    "        y:训练集样本对应的标签\n",
    "        learning_rate：学习率\n",
    "        batch_size:批量大小\n",
    "        epochs：迭代轮数\n",
    "        '''\n",
    "        # 计算输出层\n",
    "        output = self.feedforward(self.x_)\n",
    "\n",
    "        # 代价函数 J =-(Σy.logaL)/n    .表示逐元素乘\n",
    "        cost = tf.reduce_mean(-tf.reduce_sum(self.y_ * tf.log(output), axis=1))\n",
    "\n",
    "        # 求解\n",
    "        # Question3：如果使用Adam优化算法，请实现。\n",
    "        train = \n",
    "\n",
    "        # 使用会话执行图\n",
    "\n",
    "        # 初始化变量 必须在train之后\n",
    "        self.sess.run(tf.global_variables_initializer())\n",
    "\n",
    "        # 训练集长度\n",
    "        n = training_x.shape[0]\n",
    "\n",
    "        # 开始迭代 使用Adam优化的随机梯度下降法\n",
    "        for i in range(epochs):\n",
    "            # 预取图像和label并随机打乱\n",
    "            random.shuffle([training_x, training_y])\n",
    "            x_batches = [training_x[k:k + batch_size] for k in range(0, n, batch_size)]\n",
    "            y_batches = [training_y[k:k + batch_size] for k in range(0, n, batch_size)]\n",
    "\n",
    "            # 开始训练\n",
    "            for x_batch, y_batch in zip(x_batches, y_batches):\n",
    "                train.run(feed_dict={self.x_: x_batch, self.y_: y_batch})\n",
    "\n",
    "                # 计算每一轮迭代后的误差 并打印\n",
    "            train_cost = cost.eval(feed_dict={self.x_: training_x, self.y_: training_y})\n",
    "            print('Epoch {0} Training set cost {1}:'.format(i, train_cost))\n",
    "\n",
    "    def predict(self, test_x):\n",
    "        '''\n",
    "        对输入test_x样本进行预测\n",
    "        '''\n",
    "        output = self.feedforward(self.x_)\n",
    "        # 使用会话执行图\n",
    "        return output.eval(feed_dict={self.x_: test_x})\n",
    "\n",
    "    def accuracy(self, x, y):\n",
    "        '''\n",
    "        返回值准确率\n",
    "        x:测试样本集合\n",
    "        y:测试类别集合\n",
    "        '''\n",
    "        output = self.feedforward(self.x_)\n",
    "        correct = tf.equal(tf.argmax(output, 1), tf.argmax(self.y_, 1))  # 返回一个数组 表示统计预测正确或者错误\n",
    "        accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))  # 求准确率\n",
    "        # 使用会话执行图\n",
    "        return accuracy.eval(feed_dict={self.x_: x, self.y_: y})\n",
    "\n",
    "    def cost(self, x, y):\n",
    "        '''\n",
    "        计算代价值\n",
    "        '''\n",
    "        # 计算输出层\n",
    "        output = self.feedforward(self.x_)\n",
    "        # 代价函数 J =-(Σy.logaL)/n    .表示逐元素乘\n",
    "        cost = tf.reduce_mean(-tf.reduce_sum(self.y_ * tf.log(output), axis=1))\n",
    "        # 使用会话执行图\n",
    "        return cost.eval(feed_dict={self.x_: x, self.y_: y})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "开始测试，输出训练结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 0 Training set cost 0.349979043006897:\n",
      "Epoch 1 Training set cost 0.2769828140735626:\n",
      "Epoch 2 Training set cost 0.2350216656923294:\n",
      "Epoch 3 Training set cost 0.20261412858963013:\n",
      "Epoch 4 Training set cost 0.1762160211801529:\n",
      "Epoch 5 Training set cost 0.15441502630710602:\n",
      "Epoch 6 Training set cost 0.13628120720386505:\n",
      "Epoch 7 Training set cost 0.12107125669717789:\n",
      "Epoch 8 Training set cost 0.10826492309570312:\n",
      "Epoch 9 Training set cost 0.0973438173532486:\n",
      "输出权重维数：\n",
      "(784, 1024)\n",
      "(1024, 10)\n",
      "输出偏置维数：\n",
      "(1024,)\n",
      "(10,)\n",
      "准确率: 0.9672\n"
     ]
    }
   ],
   "source": [
    "nn = network([784, 1024, 10])\n",
    "nn.fit(mnist.train.images, mnist.train.labels, 0.0001, 64, 10)\n",
    "weights = nn.sess.run(nn.weights)\n",
    "print('输出权重维数：')\n",
    "for weight in weights:\n",
    "    print(weight.shape)\n",
    "print('输出偏置维数：')\n",
    "biases = nn.sess.run(nn.biases)\n",
    "for biase in biases:\n",
    "    print(biase.shape)\n",
    "print('准确率:', nn.accuracy(mnist.test.images, mnist.test.labels))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:tensorbase]",
   "language": "python",
   "name": "conda-env-tensorbase-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
